home *** CD-ROM | disk | FTP | other *** search
/ BBS Toolkit / BBS Toolkit.iso / rbbs_pc / 172aasm.zip / QBARCV4.ASM < prev    next >
Assembly Source File  |  1989-04-05  |  45KB  |  1,676 lines

  1.     page    74,132
  2.     title    ARCV - Verbose ARC directory listing
  3.  
  4. ;    Special version of ARCV to be called by QB program
  5. ; usage:
  6. ;
  7. ;    CALL ARCV (Workname$,"filename[.PAK]", RETCD%)             ' CPC151AC
  8. ;
  9. ; notes:
  10. ;    This code originated from ARCV 1.15d - Verbose ARC directory display
  11. ;    written by V.Buerg and was modified to run as a called routine under
  12. ;    Microsoft QuickBasic. It was further modified to allow PAK files by
  13. ;    Robert J. Simoneau.
  14. ;
  15. ;    Change 9/14/86 to dis-allow wildcards
  16. ;    Change 1/1/87 to recognize squash format
  17. ;    Change 2/18/87 to support network usage - - - - Jon Martin   ' CPC151A
  18. ;    Change 1/7/89 to support Pak files -------------Bob Simoneau
  19.  
  20. ;    Change 890320 to support ZIP files    David Kirschbaum, Toad Hall
  21. ;    - Question:  Why do we "have to look for the damned thing" when it
  22. ;      comes to finding ARC/PAK headers?  All comments are at file ends,
  23. ;      so the header should be EXACTLY where it should be .. at the end of
  24. ;      the file's compressed code.  Hacked severely to reflect this,
  25. ;      and vastly cleaning up the code.
  26. ;    - Replaced old SDIR Binary to Ascii conversion with a hacked version
  27. ;      from JMODEM .. about 10 times faster, plus offers integer conversion
  28. ;      as well as long integers.
  29. ;v1.3    - FAAR RBBS reports this sucker runs once and then just returns
  30. ;      a usage message (in the output file).
  31. ;      Trying to find out why.  Found it .. dumb mistake, not clearing
  32. ;      variables between runs.
  33. ;    - Adding true EOF testing for file pointer bumps.
  34. ;      ZIP files have a good way to find EOF (e.g., the central directory),
  35. ;      but PAK and ARC files don't.
  36. ;    - Added some more error msgs.
  37. ;    - Tightened hex output (CvH).
  38. ;    - Reduced buffer sizes to minimum (archdr and inbuf).
  39. ;
  40. ;v1.4    - Adding the new Japanese .LHZ capability.    Toad Hall
  41. ;      See LHARC10E.ZIP (available on GEnie and BBS's) for details.
  42. ;    - Neatening up total line.
  43. ;    - Found some bugs in trying to predetermine ARC/PAK EOF.
  44. ;      Fixed (hopefully).
  45. ;    - Added a bunch of [bx] references .. saved 100 bytes!
  46. ;    - Credits for LHARC (.LHZ) file header structure to:
  47. ;        Daniel Durbin
  48. ;        SysOp: Cygnus X-1 BBS        | CIS: 73447,1744
  49. ;        (805) 541-8505 (data)        | GEnie: D.DURBIN
  50. ;        EL major at PolySlo        | ddurbin@polyslo.CalPoly.EDU 
  51. ;      from his LVIEW.C code.
  52.  
  53. STDOUT    equ    1            ;Standard Output        v1.3
  54. STDERR    equ    2            ;Std Error (console)        v1.3
  55. FALSE    equ    0
  56. TRUE    equ    NOT FALSE
  57. DEBUG    equ    FALSE
  58.  
  59. Print    macro    name            ; display a field
  60.     mov    dx,offset name
  61.     call    PrintS
  62.     endm
  63.  
  64. header  struc                ; archive header
  65. aMbrflag    db    1AH        ;unique ARC/PAK flag        v1.3
  66. aCmpMeth    db    0        ;  compression code
  67. aMbrName    db    13 dup (0)    ;  file name
  68. aCmpSiz        dw    0,0        ;  file size in archive
  69. aModDate    dw    0        ;  creation date
  70. aModTime    dw    0        ;  creation time
  71. aCrc16        dw    0        ;  cyclic redundancy check
  72. aUncmpSiz    dw    0,0        ;  true file size, bytes
  73. header  ends
  74.  
  75. ARCHDRLEN    equ    29        ;size of ARC/PAK header.    v1.3
  76.  
  77. ;v1.3    ZIP Local file header structure:
  78.  
  79. zLocalEntry    STRUC
  80.   
  81. zdig0    db    50H,4BH,03H,04H    ;local file header signature    4 bytes
  82.                 ;(0x04034b50)
  83. zVerMade    dw    ?    ;version needed to extract    2 bytes
  84. zBitflag    dw    ?    ;general purpose bit flag    2 bytes
  85. zCmpMeth    dw    ?    ;compression method        2 bytes
  86. zModTime    dw    ?    ;last mod file time         2 bytes
  87. zModDate    dw    ?    ;last mod file date        2 bytes
  88. zCrc32        dw    ?,?    ;crc-32               4 bytes
  89. zCmpSiz        dw    ?,?    ;compressed size        4 bytes
  90. zUncmpSiz    dw    ?,?    ;uncompressed size        4 bytes
  91. zNameLen    dw    ?    ;filename length        2 bytes
  92. zExtraLen    dw    ?    ;extra field length        2 bytes
  93. zMbrName    db    ?    ;filename (variable size)
  94.                 ;extra field (variable size)
  95. ZLocalEntry    ENDS
  96.  
  97. ZIPHDRLEN    equ    30        ;length of initial ZIP hdr read    v1.3
  98.  
  99. ;v1.4    LZH header structure
  100.  
  101. lzhlfh    STRUC            ;Local file header
  102. lUnk1        db    ?,?    ;char unknown1[2];    ;?
  103. lCmpMeth    db    5 dup(?) ;char method[5];    ;compression method
  104. lCmpSiz        dw    ?,?    ;long csize;    ;compressed size
  105. lUncmpSiz    dw    ?,?    ;long fsize;    ;uncompressed size
  106. lModTime    dw    ?    ;int ftime;    ;last mod file time
  107. lModDate    dw    ?    ;int fdate;    ;last mod file date
  108. lFAttr        db    ?    ;char fattr;    ;file attributes
  109. lUnk2        db    ?    ;char unknown2;    ;?
  110. lNameLen    db    ?    ;char namelen;    ;filename length
  111. lMbrName    db    ?    ;char *fname;    ;filename
  112. ;lCrc16        dw    ?        ;int crc;    ;crc-16
  113. lzhlfh    ENDS
  114.  
  115. LZHHDRLEN    equ    22    ;not including lMbrName or lCrc16
  116.  
  117.  
  118. CSEG    segment public para 'CODE'
  119.     assume    CS:CSEG,DS:CSEG,ES:CSEG
  120.  
  121.     public  ArcV
  122.  
  123. ArcV    proc    far
  124.  
  125.     push    bp            ; save BASIC reg
  126.     mov    bp,sp            ; get parameter list pointer
  127.     mov    CS:stkptr,sp        ; save stack ptr
  128.     mov    CS:saveds,DS        ; save QB seg reg
  129.     mov    CS:savees,ES        ; save QB seg reg
  130.     call    Start            ; do our thing            v1.3
  131.  
  132. ;    set DOS error level and exit
  133. ;v1.3a    We aren't relying on the CF flag anymore to indicate errors.
  134. ;    Instead, check AL.
  135. ;    0 = success
  136. ;    1 = command line parm error
  137. ;    2..6 are file-related (not found, etc.)
  138. ;    11 = Invalid format (probably didn't find a member header)
  139. ;    13 = invalid data (probably a bad file header structure)
  140. ;    18 = Unexpected EOF ('no further files to be found')
  141.  
  142. Exit:    mov    sp,stkptr        ; restore entry stack value
  143.  
  144.     push    ax            ;save error value        v1.3
  145.  
  146. ;v1.3    Numerous errors could be returned
  147.  
  148.     or    al,al            ;no errors?
  149.     jz    Exit_NoErr        ;yep, ok
  150.  
  151.     mov    bx,offset errtbl    ;assume unknown error
  152.     mov    di,bx            ;various error values
  153.     mov    cx,ERRTBLLEN        ;table length
  154.     repne    scasb            ;find the offset
  155.     jnz    Err_TblDone        ;unknown, BX has table start
  156.  
  157.      dec    di            ;back up to actual error
  158.      sub    di,bx            ;current psn - start = relative nr
  159.      mov    bx,di            ;into BX for msg offset
  160.  
  161. Err_TblDone:
  162.     shl    bx,1            ;*2 for words
  163. Err_Unk:
  164.     add    bx,offset errmsgtbl    ;table of addresses
  165.     mov    dx,[bx]            ;ptr to string
  166.     call    PrintS            ;output error msg
  167.         
  168. Exit_NoErr:
  169.  
  170.     mov    bx,word ptr outhdl    ; close listing file
  171.     cmp    bl,STDERR        ;never opened or STDERR?    v1.3
  172.     jna    Exit1            ;not a real handle        v1.3
  173.      mov    ah,3eh            ;close file handle
  174.      int    21h
  175. Exit1:
  176.     mov    bx,word ptr archdl    ;close ARC/PAK/ZIP file        v1.3
  177.     or    bx,bx            ; if it was opened        v1.3
  178.     jz    Exit2            ; nope                v1.3
  179.      mov    ah,3EH            ;close file handle        v1.3
  180.      int    21H            ;                v1.3
  181. Exit2:                    ;                v1.3
  182.  
  183. ;v1.3    Adding a test to insure we switched DTAs
  184. ;    (so we don't blow away the caller's DTA with a vector 0:0!)
  185.  
  186.     lds    dx,dword ptr savedta    ;get orig DTA vector
  187.     or    dx,dx            ;did we ever get it?
  188.     jz    Exit_NoDTA        ;nope
  189.     mov    ax,DS            ;check out seg
  190.     or    ax,ax
  191.     jz    Exit_NoDTA        ;nope
  192.      mov    ah,1ah            ;set DTA
  193.      int    21h
  194. Exit_NoDTA:
  195.  
  196.     lds    ax,dword ptr CS:saveds    ;recover calling seg regs    v1.3
  197.                     ;(low word is orig ES)        v1.3
  198.     mov    ES,ax
  199.     ASSUME    DS:NOTHING,ES:NOTHING    ;a reminder
  200.  
  201.     pop    ax            ;restore error level        v1.3
  202.     xor    ah,ah            ;insure msb clear        v1.3a
  203.  
  204.     mov    bp,sp            ; parm ptr from entry
  205.     mov    6[bp],ax        ;return retcd variable        v1.3
  206.     pop    bp
  207.     ret    6            ; clear parms from stack     ' CPC151A
  208.  
  209.     subttl    '--- constants, equates and work areas'
  210.     page
  211.  
  212. CR    equ    13
  213. LF    equ    10
  214. BEL    equ    7
  215. TAB    equ    9
  216.  
  217. STOPPER equ    0        ; end of display line indicator
  218. ARCMARK equ    26        ; special archive marker
  219. ARCVER  equ    10        ; highest compression code used
  220.  
  221.     even            ;v1.3a
  222.  
  223. stkptr  dw    0        ; stack pointer upon entry
  224.  
  225. arctitl db    CR,LF,'Archive:  '    ;keep this even            v1.3a
  226. saveds  dw    0        ; QB seg reg
  227. savees  dw    0        ; QB seg reg
  228.  
  229.     subttl    '--- i/o control variables'
  230.     page
  231.  
  232. INBUFSZ equ    128    ;512    ; size of input buffer            v1.3
  233.  
  234. ;v1.3    Completely reordered these runtime variables
  235. ;    so we can purge them with one fell swoop
  236.  
  237. PURGESTART    equ    $    ;                    v1.3
  238.  
  239. totsf    dw    0,0        ; average stowage factor
  240. totlen  dw    0,0        ; total of file lengths
  241. totsize dw    0,0        ; total of file sizes
  242. totmbrs dw    0        ; total number of files
  243.  
  244. archdl  dw    0        ; file handle
  245. fileptr dw    0        ; ptr to filename part of arcname
  246. arclen    dw    0        ;full archive filename length        v1.3
  247. arcname db    76 dup (0)
  248.  
  249. outhdl  dw    0        ; handle for output listing        v1.3
  250. templen    dw    0        ;output filename length            v1.3
  251. temp    db    76 dup (0)    ; and temporary file name
  252.  
  253. filelen    dw    0,0        ;absolute archive file length        v1.3a
  254. curpsn    dw    0,0        ;remember current file pointer psn    v1.3a
  255.  
  256. savedta dw    0,0        ; addr of QB dta
  257. dta    db    48 dup (0)    ; data transfer area
  258.  
  259.     even            ;                    v1.3
  260.  
  261. PURGELEN    EQU    ($ - PURGESTART) SHR 1    ;amount to purge each run v1.3
  262.  
  263. ;    display lines for verbose
  264.  
  265. vhdr    db    CR,LF
  266.  db CR,LF,'Name          Length    Stowage    SF   Size now  Date       Time    CRC '
  267.  db CR,LF,'============  ========  ========  ====  ========  =========  ======  ===='
  268.  db CR,LF            ;v1.4
  269.  db STOPPER
  270.  
  271. ;vline    db    CR,LF
  272. vline    label    byte        ;v1.4
  273. vname    db    14 dup (' ')
  274. vlength db    '          '    ; length in archive            v1.3
  275. vstyle  db    '          '    ; compression method
  276. vfactor db    ' xx%  '    ; compression factor
  277. vsize    db    10 dup (' ')    ; actual file bytes
  278. vdate    db    'dd '        ; creation date
  279.  vmonth db    'mmm '
  280.  vyear  db    'yy  '
  281.  vtime  db    'hh:mm   '    ; creation time
  282.  vcrc    db    'xxxx'        ; crc in hex
  283.     db    CR,LF        ;v1.4
  284.     db    STOPPER
  285.  
  286. hundred dw    100        ; for computing percentages
  287.  
  288. ;    final totals line
  289.  
  290. vthdr    db '------    --- --------            ----  --------',CR,LF    ;v1.4
  291.     db    '*Total    '                        ;v1.4
  292.  vtmbrs db    '    '
  293.  vtlen  db    8 dup (' '),'  '
  294.     db    10 dup (' ')
  295.  vtsf    db    '   %  '
  296.  vtsize db    8 dup (' ')
  297.     db    CR,LF        ; for tom
  298.     db    STOPPER
  299.  
  300.  sign    db    ' '
  301.  
  302. styles  db    '  ----- '    ; 1 = old, no compression
  303.     db    '  ----- '    ; 2 = new, no compression
  304.     db    ' Packed '    ; 3 = dle for repeat chars
  305.     db    'Squeezed'    ; 4 = huffman encoding
  306.     db    'crunched'    ; 5 = lz, no dle
  307.     db    'crunched'    ; 6 = lz with dle
  308.     db    'Crunched'    ; 7 = lz with readjust
  309.     db    'Crunched'    ; 8 = lz with readjust and dle
  310.     db    'Squashed'    ; 9 = 13-bit lz with no dle
  311.     db    ' Crushed'    ;10 = Pak10 file ---------Bob Simoneau
  312.  
  313. ;v1.3    ZIP compression types:
  314.  
  315. zstyles    label    byte
  316.     db    '  Stored'    ;0 - The file is stored (no compression)
  317.     db    '  Shrunk'    ;1 - The file is Shrunk
  318.     db    'Reduced1'    ;2 - Reduced with compression factor 1
  319.     db    'Reduced2'    ;3 - Reduced with compression factor 2
  320.     db    'Reduced3'    ;4 - Reduced with compression factor 3
  321.     db    'Reduced4'    ;5 - Reduced with compression factor 4
  322.  
  323. ;v1.4    LZH compression types are already coded as 5 chars of text
  324. ;    in the compressed file.
  325. ;    All we need to do is pad them out to the correct width.
  326.  
  327. months  db    'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec '
  328.  
  329. ARCPAK    =    0            ;                v1.3
  330. ZIP    =    1            ;                v1.4
  331. LZH    =    2            ;                v1.4
  332. ftype    db    ZIP            ;flag which type file        v1.3
  333.  
  334. ;v1.4    4 types of archive file
  335.  
  336. ziptype    db    'ZIP'
  337. arctype    db    'ARC'
  338. paktype    db    'PAK'
  339. lzhtype    db    'LZH'            ;v1.4
  340. larctype db    'LZS'            ;v1.4 not enabled for now
  341.  
  342. ;zfilesig db    50H,4BH,03H,04H        ;local file header signature    v1.3
  343. ;zdirsig db    50H,4BH,01H,02H        ;central file header signature    v1.3
  344.  
  345. ZSIG    equ    4B50H            ;unique ZIP signature        v1.4
  346. ZFILESIG equ    0403H            ;file member signature        v1.4
  347. ZDIRSIG    equ    0201H            ;central file header signature    v1.4
  348.  
  349. ;v1.3    Centralizing errors at the exit point
  350.  
  351. ;    1 = command line parm error
  352. ;    2..6 are file-related (not found, etc.)
  353. ;    11 = Invalid format (probably didn't find a member header)
  354. ;    12 = Invalid file type (not an ARC, PAK, ZIP)
  355. ;    13 = invalid data (probably a bad file header structure)
  356. ;    18 = Unexpected EOF ('no further files to be found')
  357.  
  358. errtbl db    0,1,2,3,4,5,6,11,12,13,18,25,27,29,30            ;v1.3a
  359. ERRTBLLEN    equ    $ - errtbl
  360.  
  361. errmsgtbl dw    msg0,msg1,msg2,msg3                    ;v1.3a
  362.     dw    msg4,msg5,msg6,msg11
  363.     dw    msg12,msg13,msg18,msg25
  364.     dw    msg27,msg29,msg30
  365.  
  366. msg0    db    'Unknown error',0
  367.  
  368. msg1    db    'Invalid function number',0
  369. msg2    db    'Archive file not found',0
  370. msg3    db    'Path not found',0
  371. msg4    db    'No handle available',0
  372. msg5    db    'Access denied',0
  373. msg6    db    'Invalid handle',0
  374. msg11    db    'Archive header error',0
  375. msg12    db    'Invalid file type',0
  376. msg13    db    'Archive format error',0
  377. msg18    db    'No further files to be found',0
  378. msg25    db    'Disk seek error',0
  379. msg27    db    'Disk sector not found',0
  380. msg29    db    'Write error',0
  381. msg30    db    'Read error',0
  382.  
  383.  
  384.     subttl    '--- mainline processing'
  385.     page
  386. ;
  387. Start    proc    near            ;                v1.3
  388.  
  389.     mov    ax,CS            ;just set ES for now        v1.3
  390.     mov    ES,ax
  391.     ASSUME    DS:NOTHING,ES:CSEG    ;a reminder            v1.3a
  392.  
  393. ;v1.3    Insure all variables are cleared
  394.     cld
  395.     mov    di,offset PURGESTART
  396.     xor    ax,ax            ;clear all the variables    v1.3
  397.     mov    cx,PURGELEN        ;nr words to clear        v1.3
  398.     rep    stosw            ;                v1.3
  399.  
  400. ;v1.3    Move first parameter (output filename) into code space
  401.  
  402.     mov    si,word ptr 10[bp]    ; ptr to parameter vector    ' CPC151A
  403.     lodsw                ; get string length         ' CPC151A
  404.     mov    cx,ax            ;                 ' CPC151A
  405.     jcxz    Copy_Parm2        ;empty, forget it        v1.3
  406.      mov    di,offset templen    ;str length            v1.3
  407.      stosw                ;save length            v1.3
  408.      mov    si,[si]            ; get string offset        v1.3a
  409.      rep    movsb            ;copy in the string        v1.3
  410.  
  411. Copy_Parm2:
  412.  
  413. ;v1.3    Now copy 2d parameter (target archive filename)
  414.  
  415.     mov    si,word ptr 8[bp]    ; ptr to parameter vector
  416.     lodsw                ; get string length
  417.     mov    cx,ax            ;                v1.3
  418.     jcxz    Parm2_Done        ;forget it            v1.3
  419.      mov    di,offset arclen    ;archive name length        v1.3
  420.      stosw                ;save length            v1.3
  421.      mov    si,[si]            ; get string offset        v1.3
  422.      mov    ah,'a'            ;constant for uppercasing    v1.3
  423. Parm2_Upper:                ;                v1.3
  424.      lodsb                ;snarf char            v1.3
  425.      cmp    al,ah            ;need uppercasing?        v1.3
  426.      jb    Parm2_NoU        ;nope                v1.3
  427.       sub    al,20H            ;uppercase it            v1.3
  428. Parm2_NoU:                ;                v1.3
  429.      stosb                ;                v1.3
  430.      loop    Parm2_Upper        ;                v1.3
  431.  
  432. Parm2_Done:
  433.  
  434. ;v1.3    All done with DS
  435.  
  436.     mov    ax,CS            ;                v1.3
  437.     mov    DS,ax            ;                v1.3
  438.     ASSUME    DS:CSEG,ES:CSEG        ;a reminder            v1.3a
  439.  
  440.     mov    ax,STDERR        ;assume no output filename    v1.3a
  441.     cmp    temp,0            ;any output filename?        v1.3
  442.     jz    Temp_Opened        ;nope, use STDERR        v1.3a
  443.  
  444. ;v1.3    Forcing output file to STDERR for debugging.
  445. ;v1.3     mov    al,1            ; will show usage        v1.3
  446. ;v1.3     ret                ;back to Exit            v1.3
  447.  
  448. ;v1.3a     mov    ax,STDERR        ;force to STDERR        v1.3
  449. ;v1.3a     jmp    short Temp_Opened    ;continue            v1.3
  450.  
  451. ;Got_Temp:
  452.     mov    dx,offset temp        ; open temporary file for output
  453.     xor    cx,cx            ;no special attributes        v1.3
  454.     mov    ah,3ch            ;create file
  455.     int    21h
  456.     jnb    Temp_Opened        ;fine                v1.3
  457.      ret                ;back to Exit, AL=error code    v1.3
  458.                     ;CF set                v1.3a
  459. Temp_Opened:
  460.     mov    outhdl,ax        ;save handle
  461.  
  462. ;v1.3    Parse the target archive name
  463. ;    Separate path from name
  464. ;    Insure it's an ARC, PAK or ZIP type.
  465.  
  466.     mov    di,offset arclen    ;archive name length        v1.3
  467.     mov    ax,[di]            ;snarf length            v1.3a
  468.     inc    di            ;bump to name proper        v1.3a
  469.     inc    di            ;                v1.3a
  470.     mov    cx,ax            ;into CX for scans to come    v1.3a
  471.     jcxz    No_ArcName        ;no length, ergo no name    v1.3a
  472.  
  473.     mov    dx,ax            ;save in DX for later        v1.3
  474.     xor    al,al            ;will scan for AsciiZ terminator v1.3
  475.     cmp    [di],al            ;no name at all?        v1.3
  476.     jnz    Got_ArcName        ;yep                v1.3
  477.  
  478. No_ArcName:
  479.      mov    al,2            ;'Archive file not found'    v1.3
  480.      ret                ;back to Exit            v1.3
  481.  
  482. Got_ArcName:
  483.  
  484. ;v1.3    We have some sort of target name.
  485. ;    But is it a legal type?
  486. ;    DX = filename length
  487. ;    DI -> archive filename (arcname)
  488.  
  489.     add    di,dx            ;+ length -> last char+1    v1.3
  490.     dec    di            ;back up to last char        v1.3
  491.     mov    bx,di            ;BX -> last char        v1.3
  492.  
  493.     mov    al,'\'            ;look for normal path delimiter    v1.3
  494.     mov    cx,dx            ;length for scan        v1.3
  495.     std                ;backwards scanning now        v1.3
  496.     repne    scasb            ;                v1.3
  497.     jz    Got_Start        ;found one            v1.3
  498.  
  499. ;Ugh .. tired of typing in v1.3's!
  500.  
  501.     mov    di,bx            ;back to end
  502.     mov    cx,dx            ;restore length
  503.     mov    al,'/'            ;funny path delimiter
  504.     repne    scasb
  505.     jz    Got_Start        ;found one
  506.  
  507.     mov    di,bx            ;back to end .. sigh ..
  508.     mov    cx,dx            ;restore length
  509.     mov    al,':'            ;ok, how about a drive?
  510.     repne    scasb
  511.     jnz    No_Paths        ;nope, DI -> name start
  512.  
  513. Got_Start:
  514.     inc    di            ;bump up to the separator
  515. No_Paths:
  516.     inc    di            ;bump to the first name char
  517.     cld                ;forward again
  518.     mov    fileptr,di        ;remember real filename start
  519.  
  520. ;v1.4    You MUST specify the type .. .ARC, .PAK, .ZIP, or .LZH.
  521. ;    If .ARC or .PAK, we'll use the old code to display ARC-type
  522. ;    files.
  523. ;v1.4    Else if ZIP or LZH, it's a totally new format!
  524. ;    We remember the type archiving format in 'ftype'.
  525.  
  526. ;v1.3    DS:SI -> filename's first char.
  527.  
  528.     mov    al,'.'            ;find the separator        v1.3
  529.     mov    cx,word ptr 12        ;max of 12 chars        v1.3
  530.     repne    scasb            ;find it            v1.3
  531.     jnz    BadType            ;forget it            v1.3
  532.  
  533.     mov    dx,di            ;save pointer to file type    v1.3
  534.                     ;(just past the separator)    v1.3
  535.     mov    ax,3            ;3 chars constant
  536.  
  537.     mov    ftype,ZIP        ;assume ZIP
  538.  
  539.     mov    si,offset ziptype    ;is it a ZIP?
  540.     mov    di,dx            ;back to filename type
  541.     mov    cx,ax            ;3 chars
  542.     repz    cmpsb            ;compare
  543.     jz    Got_Type        ;a match
  544.  
  545.     mov    ftype,ARCPAK        ;ok, assume ARC or PAK        v1.3a
  546.  
  547.     mov    si,offset arctype    ;is it an ARC?            v1.3
  548.     mov    di,dx            ;back to filename type
  549.     mov    cx,ax            ;3 chars
  550.     repz    cmpsb            ;compare
  551.     jz    Got_Type        ;a match
  552.  
  553.     mov    si,offset paktype    ;is it a PAK?
  554.     mov    di,dx            ;back to filename type
  555.     mov    cx,ax            ;3 chars
  556.     repz    cmpsb            ;compare
  557.     jz    Got_Type        ;a match
  558.  
  559. ;v1.4    Adding .LZH types
  560.     mov    ftype,LZH        ;ok, assume .LZH file        v1.4
  561.  
  562.     mov    si,offset lzhtype    ;is it an LZH?
  563.     mov    di,dx            ;back to filename type
  564.     mov    cx,ax            ;3 chars
  565.     repz    cmpsb            ;compare
  566.     jz    Got_Type        ;a match
  567.  
  568. BadType:
  569.      mov    al,12            ;'Invalid file type'        v1.3a
  570.      ret                ;back to Exit            v1.3
  571.  
  572. Got_Type:                ;v1.3
  573.  
  574. ;    find first matching file
  575.  
  576.     push    ES
  577.     mov    ah,2fh            ; get current dta ptr
  578.     int    21h            ; returned in ES:bx
  579.     mov    savedta,ES
  580.     mov    savedta[2],bx
  581.     pop    ES
  582.  
  583.     mov    dx,offset dta        ; set local dta for murkers
  584.     mov    ah,1ah
  585.     int    21h
  586.  
  587.     call    OpenArc            ; see if archive exists
  588. ;    jb    ArcV_X            ;nope, return, AL = error    v1.3
  589.     jnb    ArcV1            ;ok
  590.      jmp    ArcV_X            ;nope, return, AL=error        v1.4
  591.  
  592. ;v1.3a    Display archive filename, header,
  593. ;    then into a loop for each archive member.
  594.  
  595. ArcV1:    mov    dx,fileptr        ;pointer to filename        v1.3a
  596.     call    PrintS            ;display, CR/LF            v1.3a
  597.     jb    ArcV_X            ;output failed            v1.3a
  598.  
  599.     Print    vhdr
  600.     jb    ArcV_X            ;output failed, AL = error    v1.3
  601.  
  602. ArcVNext:
  603. IF    DEBUG
  604.     Print    debug1
  605.     jmp    short debugj1
  606. debug1    db    'Calling GetHdr',CR,LF,0
  607. debugj1:
  608. ENDIF
  609.     call    GetHdr            ; load next header
  610.     jb    ArcV_NoHdr        ;failed somehow, AL=error    v1.3a
  611.                     ;(could be EOF, which is ok)    v1.3a
  612. IF    DEBUG
  613.     Print    debug2
  614.     jmp    short debugj2
  615. debug2    db    'Calling ArcVgo',CR,LF,0
  616. debugj2:
  617. ENDIF
  618.     call    ArcVgo            ;format, write out file report
  619.     jb    Arcv_NoHdr        ;something failed, AL=error    v1.3a
  620.  
  621. IF    DEBUG
  622.     Print    debug3
  623.     jmp    short debugj3
  624. debug3    db    'Calling Bump_ArcPtrs',CR,LF,0
  625. debugj3:
  626. ENDIF
  627.     call    Bump_ArcPtrs        ;bump to next archive file    v1.3
  628.     jnb    ArcVNext        ;loop if ok, else AL=error    v1.3a
  629.                     ;(could be EOF)            v1.3a
  630.  
  631. ArcV_NoHdr:
  632.     cmp    archdr.aCmpMeth,0    ; archive eof?
  633.     jnz    ArcV_X            ;nope, something else happened    v1.3
  634.  
  635.     cmp    totmbrs,0        ;any totals?            v1.3
  636.     jz    ArcV_X            ;nope                v1.3
  637.      push    ax            ;save previous error value    v1.3
  638.      call    Format_Totals        ;yep, format and output        v1.3
  639.      pop    ax            ;restore prev err value        v1.3
  640.  
  641. ArcV_X:    ret                ;AL=error            v1.3a
  642.  
  643. Start    endp                ;                v1.3
  644.  
  645.  
  646. ;v1.3    Format, display single line for each member
  647. ;    On success, return:
  648. ;     CF clear
  649. ;     AL = 0
  650. ;    On error, return:
  651. ;     CF set (because of output write fail)
  652. ;     AL = error code
  653.  
  654. ArcVgo    proc    near
  655.     mov    di,offset vname        ; copy file name
  656.     mov    si,offset archdr.aMbrName
  657.     mov    cx,word ptr 13        ;up to 12 chars long, AsciiZ 0
  658. ArcV3:
  659.     lodsb
  660.     or    al,al            ; end of name?            v1.3
  661.     je    ArcV4
  662.      stosb
  663.      loop    ArcV3
  664.      jmp    short ArcV5
  665.  
  666. ArcV4:
  667.     mov    al,' '            ; pad with blanks
  668.     rep    stosb
  669. ArcV5:
  670. ; reduce the size/length to word values
  671.  
  672.     mov    bx,offset archdr.aCmpSiz    ;-> compressed size    v1.4
  673.     mov    cx,[bx]            ;.lo                v1.4
  674.     mov    dx,2[bx]        ;.hi                v1.4
  675.     mov    bx,offset archdr.aUncmpSiz    ;-> uncompressed size    v1.4
  676.     mov    ax,2[bx]        ;.hi                v1.4
  677.     mov    bx,[bx]            ;.lo                v1.4
  678.  
  679. ArcV51: or    ax,ax            ; big number?
  680.     jz    ArcV52            ; nope, can use it
  681.      shr    ax,1            ; yup, divide by two
  682.      rcr    bx,1
  683.      shr    dx,1
  684.      rcr    cx,1
  685.      jmp    short ArcV51
  686.  
  687. ArcV52:
  688.     mov    ax,bx            ; low word of actual size
  689.     mov    sign,' '
  690.     cmp    ax,cx            ; arc member is larger?
  691.     jb    ArcV520
  692.      sub    ax,cx            ; amount saved
  693.      jmp    short ArcV56
  694.  
  695. ArcV520:
  696.     sub    ax,cx
  697.     neg    ax
  698.     mov    sign,'-'
  699.  
  700. ArcV56:
  701.     mul    hundred            ; to percentage
  702.     add    ax,50
  703.     adc    dx,0            ; round up percent
  704.     or    bx,bx            ; empty file?
  705.     jnz    ArcV53
  706.      mov    ax,100
  707.      jmp    short ArcV54
  708.  
  709. ArcV53: div    bx
  710. ArcV54:
  711.     cmp    ax,100            ; archive fouled?
  712.     jbe    ArcV55
  713.      sub    ax,ax
  714. ArcV55:
  715.     mov    di,offset vfactor-2    ;format stowage factor        v1.3
  716.     call    Asciify            ;display AX
  717.  
  718.     mov    al,sign
  719.     mov    vfactor,al
  720.  
  721.     mov    cx,word ptr 3        ;gonna need it in a sec        v1.4
  722.     cmp    ftype,LZH        ;LZH type? (compression method    v1.4
  723.                     ; is already text)        v1.4
  724.     jnz    ArcV_GetStyles        ;nope                v1.4
  725.  
  726. ;v1.4    The LZH compression method (5 chars) is still in inbuf.
  727.  
  728.     mov    si,offset inbuf.lCmpMeth    ;-> 5-char compression    v1.4
  729.                         ;   method string    v1.4
  730.     mov    di,si
  731.     add    di,5            ;point to beyond chars        v1.4
  732.     mov    ax,'  '            ;need 3 trailing blanks        v1.4
  733.     stosw
  734.     stosb
  735.     mov    di,offset vstyle+1    ;indent to be neat        v1.4
  736.     jmp    short ArcV_GotStyle    ;skip                v1.4
  737.  
  738. ArcV_GetStyles:                ;                v1.4
  739.  
  740.     mov    si,offset zstyles    ;assume ZIP            v1.3
  741.     cmp    ftype,ZIP        ;ZIP file?            v1.3
  742.     jz    ArcV55A            ;yep                v1.3
  743.      mov    si,offset styles    ;ARC or PAK            v1.3
  744. ArcV55A:                ;                v1.3
  745.  
  746.     sub    bx,bx            ; determine style
  747.     mov    bl,archdr.aCmpMeth
  748.     dec    bl            ;adjust for table offset    v1.3
  749. ;v1.4    mov    cl,3            ; eight bytes each entry
  750. ;v1.4    CX = 3 (eight bytes each entry)
  751.     shl    bx,cl    ;*8
  752.  
  753.     add    si,bx            ;point into style table        v1.3
  754.     mov    di,offset vstyle
  755.  
  756. ArcV_GotStyle:                ;                v1.4
  757.     inc    cx            ;CX=4=words to move        v1.4
  758.     rep    movsw            ;                v1.3
  759.  
  760.     mov    bx,offset archdr.aCmpSiz    ;-> compressed size    v1.4
  761.     mov    ax,[bx]            ;.lo                v1.4
  762.     mov    dx,2[bx]        ;.hi                v1.4
  763.     mov    bx,offset totsize    ;-> accumulated compressed size    v1.4
  764.     add    [bx],ax            ;.lo                v1.4
  765.     adc    2[bx],dx        ;.hi                v1.4
  766.  
  767.     mov    di,offset vsize        ;format file size        v1.3
  768.     call    Asciify_Long        ;                v1.3
  769.  
  770.     mov    bx,offset archdr.aUncmpSiz    ;-> uncompressed size    v1.4
  771.     mov    ax,[bx]            ;.lo                v1.4
  772.     mov    dx,2[bx]        ;.hi                v1.4
  773.     mov    bx,offset totlen    ;-> total length accumulator    v1.4
  774.     add    [bx],ax            ;.lo                v1.4
  775.     adc    2[bx],dx        ;.hi                v1.4
  776.     
  777.     mov    di,offset vlength    ;format file length        v1.3
  778.     call    Asciify_Long        ;                v1.3
  779.  
  780.     mov    ax,archdr.aModDate    ; format file date
  781.     call    GetDate
  782.  
  783.     mov    ax,archdr.aModTime    ; format file time
  784.     call    GetTime
  785.  
  786.     mov    ax,archdr.aCrc16    ; format crc in hex
  787.     mov    di,offset vcrc
  788.     call    Cvh
  789.  
  790.     inc    totmbrs            ;NOW bump total count        v1.3a
  791.     Print    vline            ; display this file info
  792.                     ;(may return error)        v1.3a
  793.     ret
  794.  
  795. ArcVgo    endp
  796.  
  797.  
  798.     subttl    '--- load next archive header'
  799.     page
  800.  
  801. ;v1.3    Adding ZIP file searching
  802. ;v1.3a    For ARC/PAK files, now testing to see if we're at the archive
  803. ;    file end.  If so (a proper file), return with EOF (CF set
  804. ;    but AL=0).
  805. ;    Archive files may have picked up some garbage on the end
  806. ;    (from XMODEM xfers, whatever).  We'll see if we at LEAST have
  807. ;    enough data for an archive header.
  808. ;    If not, assume EOF, ignoring garbage.
  809. ;    If there's more than 29 bytes of garbage .. the header will be
  810. ;    garbage and we're gonna report a format error .. but that's ok for now.
  811. ;    Zip files have a definite ending (the central directory,
  812. ;    and they'll look out for their own endings.
  813. ;
  814. ;    Also returning CF and AL per any errors.
  815.  
  816. GetHdr  proc    near
  817.  
  818.     xor    ax,ax            ;handy 0
  819.     mov    archdr.aCmpMeth,al    ;assume archive EOF
  820.  
  821.     cmp    ftype,ZIP        ;doing ZIP files?
  822.     jnz    GH_NotZip        ;nope                v1.4
  823.      jmp    Get_ZipHdr        ;yep, they look out for themselves
  824.  
  825. GH_NotZip:
  826.     cmp    ftype,LZH        ;doing an LZH file?        v1.4
  827.     jnz    GH_ArcPak_Hdr        ;nope                v1.4
  828.      jmp    Get_LZHHdr        ;yep                v1.4
  829.  
  830. GH_ArcPak_Hdr:                ;                v1.4
  831.  
  832. ;v1.3    New code
  833. ;    ARC/PAK headers look like this:
  834. ;aMbrFlag    db    1AH        ;unique header flag
  835. ;aCmpMeth    db    0        ;  compression code
  836. ;aMbrName    db    13 dup (0)    ;  file name
  837. ;aCmpSiz    dw    0,0        ;  file size in archive
  838. ;aModDate    dw    0        ;  creation date
  839. ;aModTime    dw    0        ;  creation time
  840. ;aCrc16        dw    0        ;  cyclic redundancy check
  841. ;aUncmpSiz    dw    0,0        ;  true file size, bytes
  842.  
  843.     mov    dx,offset archdr    ;read into here
  844.     mov    cx,ARCHDRLEN        ;nr bytes to read
  845.     mov    bx,archdl        ;archive file handle
  846.     mov    ah,3FH            ;read from file/device
  847.     int    21H
  848.     jnb    GH_ChkHdr        ;read ok            v1.3a
  849.      ret                ;return CF set, AL=error    v1.3a
  850.  
  851. GH_ChkHdr:
  852.     mov    bx,dx            ;DS:BX -> structure start    v1.3a
  853.  
  854.     cmp    [bx].aMbrFlag,ARCMARK    ;start of header?
  855.     jne    Hdr_InvalFmt        ;'invalid format', exit CF set
  856.  
  857.     mov    al,[bx].aCmpMeth    ;type compression
  858.     cmp    al,ARCVER        ;reasonable code?
  859.     ja    Hdr_InvalFmt        ;nope, funny stuff
  860.  
  861.     or    al,al            ; archive eof?
  862.     je    Hdr_RetCF        ;yep, done, return CF set
  863.                     ;but AL=0 = not a REAL error    v1.3a
  864.     cmp    al,1            ; old format?
  865.     jne    GetHdrX            ; if so, it's short
  866.      mov    si,offset archdr.aCmpSiz            ; CPC15-1C
  867.      mov    di,offset archdr.aUncmpSiz            ; CPC15-1C
  868.      movsw                ;                v1.3
  869.      movsw                ;                v1.3
  870. GetHdrX:
  871.     xor    al,al            ;return AL=0, success        v1.3a
  872.     clc
  873.     ret
  874.  
  875. Hdr_InvalFmt:
  876.     mov    al,0BH            ;'invalid format'
  877. Hdr_EarlyEOF:                ;                ;v1.4
  878.     mov    [bx].aCmpMeth,al    ;signal EOF or invalid format    v1.4
  879. Hdr_RetCF:
  880.     stc                ;return CF set, AL=error
  881.     ret
  882.  
  883. GetHdr    endp
  884.  
  885.  
  886. Get_ZipHdr    proc    near
  887. ;v1.4    GetHdr Subroutine for ZIP files
  888. ;v1.3    Reads in ZIP file entry.
  889. ;    Then scans for the unique file entry signature.
  890. ;    On success:
  891. ;     DS:BX -> file entry directory structure
  892. ;     CF clear
  893. ;    Else CF set for failure
  894.  
  895.     call    Read_Zip_Entry
  896.     jb    Get_ZHdrX            ;failed, AL=ERRORLEVEL
  897.  
  898.     mov    bx,offset inbuf            ;use for field base
  899.     mov    di,offset archdr.aCmpMeth    ;moving into this structure
  900.  
  901. ;v1.4    Remember, the ZIP header we'll be snarfing data from
  902. ;    looks like this:
  903. ;zVerMade    dw    ?    ;version needed to extract    2 bytes
  904. ;zBitflag    dw    ?    ;general purpose bit flag    2 bytes
  905. ;zCmpMeth    dw    ?    ;compression method        2 bytes
  906. ;zModTime    dw    ?    ;last mod file time         2 bytes
  907. ;zModDate    dw    ?    ;last mod file date        2 bytes
  908. ;zCrc32        dw    ?,?    ;crc-32               4 bytes
  909. ;zCmpSiz    dw    ?,?    ;compressed size        4 bytes
  910. ;zUncmpSiz    dw    ?,?    ;uncompressed size        4 bytes
  911. ;zNameLen    dw    ?    ;filename length        2 bytes
  912. ;zExtraLen    dw    ?    ;extra field length        2 bytes
  913. ;zMbrName    db    ?    ;filename (variable size)
  914.                 ;extra field (variable size)
  915. ;
  916. ;    and the ARC/PAK record we'll be formatting to
  917. ;    looks like this:
  918. ;aMbrFlag db    1AH
  919. ;aCmpMeth db    0            ;  compression code
  920. ;aMbrName db    13 dup (0)        ;  file name
  921. ;aCmpSiz dw    0,0            ;  file size in archive
  922. ;aModDate dw    0            ;  creation date
  923. ;aModTime dw    0            ;  creation time
  924. ;aCrc16  dw    0            ;  cyclic redunancy check
  925. ;aUncmpSiz  dw    0,0            ;  true file size, bytes
  926.  
  927.     mov    ax,[bx].zCmpMeth        ;compression method
  928.     inc    al                ;bump to be non-0
  929.     stosb                    ;->  aCmpMeth
  930.  
  931. ;For now, assuming a normal file name (no paths)
  932.  
  933.     mov    ax,[bx].zNameLen        ;filename length
  934.     and    ax,15                ;constrain to max 12 chars
  935.     mov    cx,ax                ;into CX for move
  936.     lea    si,[bx].zMbrName        ;pointer to actual filename
  937.     rep    movsb                ;do the move
  938.     xor    al,al                ;terminating 0
  939.     stosb
  940.  
  941.     mov    di,offset archdr.aCmpSiz    ;bump past name
  942.  
  943. ;    mov    ax,[bx].zCmpSiz            ;compressed size.lo
  944. ;    stosw                    ; -> aCmpSiz
  945. ;    mov    ax,[bx].zCmpSiz[2]        ;compressed size.hi
  946. ;    stosw                    ; -> aCmpSiz[2]
  947.     mov    si,offset inbuf.zCmpSiz        ;-> compressed size
  948.     movsw                    ;aCmpSiz.lo
  949.     movsw                    ;aCmpSiz.hi
  950.  
  951.     mov    ax,[bx].zModDate        ;last mod date
  952.     stosw                    ; -> aModDate
  953.     mov    ax,[bx].zModTime        ;last mod time
  954.     stosw                    ; -> aModTime
  955.     mov    ax,[bx].zCrc32            ;CRC-32 value.lo
  956.     stosw                    ; -> aCrc16
  957.  
  958. ;    mov    ax,[bx].zUncmpSiz        ;uncompressed size.lo
  959. ;    stosw                    ; -> aUncmpSiz
  960. ;    mov    ax,[bx].zUncmpSiz[2]        ;uncompressed size.hi
  961. ;    stosw                    ; -> aUncmpSiz[2]
  962.     mov    si,offset inbuf.zUncmpSiz    ;-> uncompressed size
  963.     movsw                    ;aUncmpSiz.lo
  964.     movsw                    ;aUncmpSiz.hi
  965.  
  966.     xor    ax,ax                ;return AX 0
  967.     clc                    ;return CF clear
  968. Get_ZHdrX:
  969.     ret
  970.  
  971. Get_ZipHdr    endp        ;GetHdr subroutine
  972.  
  973.  
  974.  
  975. Get_LZHHdr    proc    near
  976. ;v1.4    GetHdr Subroutine for LZH headers
  977. ;    LZH file header has already been read in to inbuf.
  978. ;
  979. ;    If all is ok, we move the appropriate LZH fields into the
  980. ;    standard ARC/PAK structure (archdr) (so far as we can).
  981. ;
  982. ;    Gleaning from the LHARCDOC documentation, the 'laCmpMeth' field
  983. ;    (5 characters) can be:
  984. ;        '-lh0-'        stored as is (no compression)
  985. ;        '-lh1-'        compressed by LZHuf coding
  986. ;    There appear to be at least two more possible compression codes
  987. ;    that may appear:  "LARC type 4 and type 5" (whatever they may be!).
  988. ;
  989. ;    Assuming this field will ALWAYS be text, we are NOT gonna try to
  990. ;    snarf some magic code number out of the field, but will just
  991. ;    protect the field (in inbuf) and move the text directly into our
  992. ;    formatted display line later.
  993. ;
  994. ;    The only way we can test this as an LZH header is to look
  995. ;    for a '-%%%-' starting at the 2d header byte (the laCmpMeth
  996. ;    field).
  997. ;
  998. ;    On success:
  999. ;     DS:BX -> file entry directory structure
  1000. ;     CF clear
  1001. ;    Else CF set for failure
  1002.  
  1003. ;v1.4    LZH files don't have a decent, clean EOF header.
  1004. ;    We have to test for near-EOF the hard way.
  1005.  
  1006.     mov    di,offset archdr.aMbrFlag    ;moving into this structure
  1007.     mov    ax,001AH            ;fake ARC/PAK flag
  1008.     stosw                    ; and EOF compression code
  1009.  
  1010.     xor    ax,ax            ;handy 0
  1011.     mov    bx,offset filelen    ;-> file length
  1012.     mov    dx,[bx]            ;file length.lo
  1013.     mov    cx,2[bx]        ;file length.hi
  1014.  
  1015.     mov    bx,offset curpsn    ;for fast access    
  1016.     cmp    cx,2[bx]        ;length.hi = psn.hi?
  1017.     jnz    GL_AddHdr        ;nope
  1018.     cmp    dx,[bx]            ;length.lo = psn.lo?
  1019.     jz    GL_TrueEof        ;yep, we're exactly at EOF
  1020.  
  1021. GL_AddHdr:
  1022.     sub    dx,LZHHDRLEN        ;sub header length
  1023.     sbb    cx,ax    ;0        ;handle the borrow
  1024.     jb    GL_Eof            ;<0, beyond EOF
  1025.     sub    dx,[bx]            ;- file psn.lo
  1026.     sbb    cx,2[bx]        ;- file psn.hi, minus any borrows
  1027.     jnb    GL_NotEof        ;not near end .. ok
  1028.  
  1029. ;There must've been junk on the file end.
  1030. ;However .. there ALWAYS seems to be junk on the end.
  1031. ; So .. we'll return no message at all (AL=0)
  1032. ;If we ever figure out how to detect a TRUE LZH EOF,
  1033. ;we can enable this ERRORLEVEL=18 business.
  1034.  
  1035. GL_Eof:
  1036. ;    mov    al,18            ;'No further files to be found'
  1037. GL_TrueEof:
  1038.     stc                ;CF set for EOF            v1.4
  1039.     ret
  1040.  
  1041. GL_NotEof:
  1042.  
  1043.     push    di            ;save ptr -> archdr.aMbrName
  1044.     call    Read_LZH_Entry
  1045.     pop    di
  1046.     jb    Get_LHdrX            ;failed, AL=ERRORLEVEL
  1047.  
  1048.     mov    bx,offset inbuf            ;use for field base
  1049.  
  1050. ;v1.4    Remember, the LZH header we'll be snarfing data from
  1051. ;    looks like this:
  1052. ;lUnk1    db    ?,?    ;char unknown1[2];    ;?
  1053. ;lCmpMeth    db    5 dup(?) ;char method[5];    ;compression method
  1054. ;lCmpSiz    dw    ?,?    ;long csize;    ;compressed size
  1055. ;lUncmpSiz    dw    ?,?    ;long fsize;    ;uncompressed size
  1056. ;lModTime    dw    ?    ;int ftime;    ;last mod file time
  1057. ;                        ; (msdos format)
  1058. ;lModDate    dw    ?    ;int fdate;    ;last mod file date
  1059. ;lfAttr        db    ?    ;char fattr;    ;file attributes
  1060. ;unknown2    db    ?    ;char unknown2;    ;?
  1061. ;lNameLen    db    ?    ;char namelen;    ;filename length
  1062. ;
  1063. ;lMbrName    db    ?    ;char *fname;    ;filename
  1064. ;;lCrc16    dw    ?    ;int crc;    ;crc-16
  1065. ;
  1066. ;    and the ARC/PAK record we'll be formatting to
  1067. ;    looks like this:
  1068. ;aMbrFlag db    1AH
  1069. ;aCmpMeth db    0            ;  compression code
  1070. ;aMbrName db    13 dup (0)        ;  file name
  1071. ;aCmpSiz dw    0,0            ;  file size in archive
  1072. ;aModDate dw    0            ;  creation date
  1073. ;aModTime dw    0            ;  creation time
  1074. ;aCrc16  dw    0            ;  cyclic redundancy check
  1075. ;aUncmpSiz  dw    0,0            ;  true file size, bytes
  1076.  
  1077.     mov    al,[bx].lNameLen        ;filename length
  1078.     and    ax,15                ;constrain to max 12 chars
  1079.     mov    cx,ax                ;into CX for move
  1080.     mov    si,offset inbuf.lMbrName    ;-> actual filename
  1081.     rep    movsb                ;do the move
  1082.     xor    al,al                ;terminating 0
  1083.     stosb
  1084.  
  1085. ;In LZH headers, the 2-byte CRC16 word lies immediately
  1086. ;after the filename.
  1087. ;Snarf it now and stuff in the ARC header.
  1088.  
  1089.     lodsw                    ;lCrc16
  1090.     push    ax                ;save a sec
  1091.  
  1092.     mov    di,offset archdr.aCmpSiz    ;bump past name
  1093.  
  1094. ;    mov    ax,[bx].lCmpSiz            ;compressed size.lo
  1095. ;    stosw                    ; -> aCmpSiz
  1096. ;    mov    ax,[bx].lCmpSiz[2]        ;compressed size.hi
  1097. ;    stosw                    ; -> aCmpSiz[2]
  1098.     mov    si,offset inbuf.lCmpSiz        ;-> compressed size
  1099.     movsw                    ;aCmpSiz.lo
  1100.     movsw                    ;aCmpSiz.hi
  1101.  
  1102.     mov    ax,[bx].lModDate        ;last mod date
  1103.     stosw                    ; -> aModDate
  1104.     mov    ax,[bx].lModTime        ;last mod time
  1105.     stosw                    ; -> aModTime
  1106.     pop    ax                ;CRC-16 value
  1107.     stosw                    ; -> aCrc16
  1108. ;    mov    ax,[bx].lUncmpSiz        ;uncompressed size.lo
  1109. ;    stosw                    ; -> aUncmpSiz
  1110. ;    mov    ax,[bx].lUncmpSiz[2]        ;uncompressed size.hi
  1111. ;    stosw                    ; -> aUncmpSiz[2]
  1112.     mov    si,offset inbuf.lUncmpSiz    ;-> uncompressed size
  1113.     movsw                    ;aUncmpSiz.lo
  1114.     movsw                    ;aUncmpSiz.hi
  1115.  
  1116.     xor    ax,ax                ;return AX 0
  1117.     clc                    ;return CF clear
  1118. Get_LHdrX:
  1119.     ret
  1120.  
  1121. Get_LZHHdr    endp            ;GetHdr Subroutine        v1.4
  1122.  
  1123.  
  1124. Read_LZH_Entry    proc    near        ;GetHdr Subroutine        v1.4
  1125.  
  1126.     mov    dx,offset inbuf            ;read into here
  1127.     mov    cx,LZHHDRLEN            ;entry structure size
  1128.                         ;(does NOT include variable
  1129.                         ; length filename, and the
  1130.                         ;two CRC bytes following the
  1131.                         ;filename)
  1132.     mov    bx,archdl            ;file handle
  1133.     call    ReadZ_It            ;try to read in header
  1134.                         ;(up to filename)
  1135.     jb    ReadL_Eof            ;failed, AL=error
  1136.  
  1137.     mov    si,dx                ;structure start
  1138.     mov    al,'-'                ;test for '-l%-' or whatever
  1139.     cmp    [si].lCmpMeth,al        ;first part of compression
  1140.                         ;method string?
  1141.     jnz    ReadL_InvalDat            ;bogus, failed
  1142.      cmp    [si].lCmpMeth+4,al        ;how about last char?
  1143.      jz    ReadL_Ok1            ;yep, fine
  1144. ReadL_InvalDat:
  1145.     mov    al,0DH                ;force to 'invalid data'
  1146. ReadL_Eof:
  1147.     mov    archdr.aCmpMeth,al        ;set per EOF or error
  1148.     stc                    ;return CF set
  1149.     ret
  1150.  
  1151. ReadL_Ok1:
  1152.     mov    dx,offset inbuf.lMbrName    ;-> lMbrName psn
  1153.     mov    cl,inbuf.lNameLen        ;length of member filename
  1154.     xor    ch,ch                ;clear msb
  1155.     call    ReadZ_It            ;read in the name
  1156.     jb    ReadL_Eof            ;failed
  1157.     add    dx,cx                ;bump buff ptr past name
  1158.     mov    cx,2                ;LZH CRC is a word
  1159.     call    ReadZ_It            ;read in the CRC word
  1160.     jb    ReadL_Eof            ;failed
  1161.     ret                    ;success
  1162.  
  1163. Read_LZH_Entry    endp            ;GetHdr Subroutine        v1.4
  1164.  
  1165.  
  1166. Read_Zip_Entry    proc    near        ;GetHdr Subroutine
  1167.  
  1168.     mov    dx,offset inbuf            ;read into here
  1169.     mov    cx,ZIPHDRLEN            ;entry structure size
  1170.                         ;(does NOT include filename or
  1171.                         ; Extra fields, which are
  1172.                         ;dynamic)
  1173.     mov    bx,archdl            ;file handle
  1174.     call    ReadZ_It            ;try to read in header
  1175.                         ;(up to filename)
  1176.     jb    ReadZ_Eof            ;failed, AL=error    v1.3a
  1177.  
  1178.     mov    si,dx                ;->file signature    v1.4
  1179.     lodsw                    ;snarf first 2 chars    v1.4
  1180.     cmp    ax,ZSIG                ;ZIP header?        v1.4
  1181.     jnz    ReadZ_InvalDat            ;nope, bogus        v1.4
  1182.     lodsw                    ;file or central sig    v1.4
  1183.     cmp    ax,ZFILESIG            ;next member?        v1.4
  1184.     jz    ReadZ_Ok1            ;yep, fine        v1.4
  1185.     cmp    ax,ZDIRSIG            ;central directory?    v1.4
  1186.                         ;(means we're done)    v1.4
  1187.     mov    al,0                ;assume yes, EOF    v1.4
  1188.     jz    ReadZ_Eof            ;yep            v1.4
  1189.  
  1190. ReadZ_InvalDat:
  1191.     mov    al,0DH                ;'Invalid data'        v1.4
  1192. ReadZ_Eof:                    ;            v1.3a
  1193.     mov    archdr.aCmpMeth,al        ;set per EOF or error    v1.3a
  1194.     stc                    ;return CF set        v1.3a
  1195.     ret
  1196.  
  1197. ReadZ_Ok1:
  1198.     mov    dx,offset inbuf.zMbrName    ;move to zFilename psn
  1199.     mov    cx,inbuf.zNameLen        ;length of member filename
  1200.                         ;fall thru to ...    v1.3a
  1201.  
  1202. ;v1.4    Common subroutine for ReadZ and Read_LZH
  1203. ;    DX -> buffer
  1204. ;    CX = bytes to read
  1205. ;    BX MUST have archdl .. so protect BX!
  1206.  
  1207. ReadZ_It:
  1208.     mov    ah,3FH                ;read from file/device
  1209.     int    21H
  1210.     jb    ReadZ_ItX            ;failed, error in AX    v1.3a
  1211.  
  1212. ;v1.4    We'll update our curpsn file pointers later
  1213. ;    when we try to read past compressed file contents.
  1214.  
  1215. ;v1.4     add    curpsn,ax            ;bump current file ptr    v1.3a
  1216.                         ;by amount read        v1.3a
  1217. ;v1.4     adc    word ptr curpsn[2],0        ;bump psn.hi if carry    v1.3a
  1218.  
  1219.      cmp    ax,cx                ;read all we expected?
  1220.      mov    ax,0                ;clear AX        v1.3a
  1221.      jz    ReadZ_ItX            ;yep, return CF clear    v1.3a
  1222.       mov    al,0BH                ;assume unexpected EOF
  1223.                         ;('invalid format')
  1224.       stc
  1225. ReadZ_ItX:
  1226.     ret                    ;CF, AL set per error    v1.3a
  1227.  
  1228. Read_Zip_Entry    endp            ;GetHdr subroutine
  1229.  
  1230.  
  1231. ;v1.3    Common subroutine
  1232. ;    Bumps archive file pointers to next entry
  1233. ;    On success, return:
  1234. ;     CF clear
  1235. ;     AL = 0
  1236. ;    On failure (e.g., couldn't move ptrs), return:
  1237. ;     CF set
  1238. ;     AL = error
  1239.  
  1240. Bump_ArcPtrs    proc    near
  1241.  
  1242.     cmp    ftype,ZIP        ;ZIP file?            v1.3
  1243.     jz    Next_ZEntry        ;bump file ptr to next entry    v1.3
  1244.  
  1245. ;v1.3    Entirely new code
  1246.  
  1247.     mov    bx,offset archdr.aCmpSiz    ;-> encoded file length    v1.4
  1248.     mov    dx,[bx]            ;.lo                v1.4
  1249.     mov    cx,2[bx]        ;.hi
  1250.     jmp    short Bump_Common    ;common code
  1251.  
  1252.  
  1253. ;v1.3    Positions ZIP file pointer to next local entry.
  1254. ;    We've already read in the entire header, plus the filename,
  1255. ;    so the file pointer should be just beyond the filename
  1256. ;    (at the Extra field).
  1257. ;    Move file pointers beyond the Extra field, and then past
  1258. ;    the actual entry data (the compressed size).
  1259.  
  1260. Next_ZEntry:
  1261.  
  1262.     mov    bx,offset inbuf            ;point back to structure
  1263.     mov    dx,[bx].zCmpSiz            ;size.lo
  1264.     mov    cx,[bx].zCmpSiz[2]        ;size.hi
  1265.     add    dx,[bx].zExtraLen        ;add in extra field length
  1266.     adc    cx,0                ;in case of carry
  1267.  
  1268. Bump_Common:
  1269.  
  1270.     mov    bx,archdl            ;file handle
  1271.     mov    ax,4201H            ;move pointer from current loc
  1272.     int    21H
  1273.     jb    Bump_X                ;seek error        v1.3a
  1274.                         ;return CF set, AL=error v1.3a
  1275.  
  1276. ;v1.4    Updating curpsn variables now
  1277. ;    so the NEXT GetHdr call will have current data.
  1278.      mov    bx,offset curpsn
  1279.      mov    [bx],ax
  1280.      mov    2[bx],dx
  1281.      xor    ax,ax                ;AX,CF clear        v1.3a
  1282. Bump_X:
  1283.     ret
  1284.  
  1285. Bump_ArcPtrs    endp
  1286.  
  1287.  
  1288. ;v1.3    Formats, displays totals
  1289.  
  1290. Format_Totals    proc    near
  1291.  
  1292.     mov    ax,totmbrs        ;total members            v1.3
  1293.     mov    di,offset vtmbrs-2    ;format total members        v1.3
  1294.     call    Asciify            ;                v1.3
  1295.  
  1296.     mov    bx,offset totlen    ;-> total actual file size    v1.4
  1297.     mov    ax,[bx]            ;.lo                v1.4
  1298.     mov    dx,2[bx]        ;.hi                v1.4
  1299.  
  1300.     push    ax            ;save totlen.lo            v1.4
  1301.     push    dx            ; and totlen.hi            v1.4
  1302.  
  1303.     mov    di,offset vtlen        ;format total actual file size    v1.3
  1304.     call    Asciify_Long        ;                v1.3
  1305.  
  1306.     mov    bx,offset totsize    ;-> total compressed file sizes    v1.4
  1307.     mov    ax,[bx]            ;.lo                v1.4
  1308.     mov    dx,2[bx]        ;.hi                v1.4
  1309.  
  1310.     push    ax            ;save totsize.lo        v1.4
  1311.     push    dx            ; and totsize.hi        v1.4
  1312.  
  1313.     mov    di,offset vtsize    ;format total archive file size    v1.3
  1314.     call    Asciify_Long        ;                v1.3
  1315.  
  1316. ; reduce the total size/length to word values
  1317.  
  1318.     pop    dx            ;totsize.hi            v1.4
  1319.     pop    cx            ;totsize.lo            v1.4
  1320.     pop    ax            ;totlen.hi            v1.4
  1321.     pop    bx            ;totlen.lo            v1.4
  1322.  
  1323. ArcV2b: or    ax,ax            ; big number?
  1324.     jz    ArcV2c            ; nope, can use it
  1325.      shr    ax,1            ; yup, divide by two
  1326.      rcr    bx,1
  1327.      shr    dx,1
  1328.      rcr    cx,1
  1329.      jmp    short ArcV2b
  1330.  
  1331. ArcV2c:
  1332.     mov    ax,bx
  1333.     mov    sign,' '        ; whata kludge
  1334.     cmp    ax,cx            ; arc is bigger than orig?
  1335.     jb    ArcV2c1
  1336.      sub    ax,cx            ; amount saved
  1337.      jmp    short ArcV2f
  1338.  
  1339. ArcV2c1:
  1340.     sub    ax,cx
  1341.     neg    ax
  1342.     mov    sign,'-'
  1343.  
  1344. ArcV2f:
  1345.     mul    hundred            ; to percentage
  1346.     add    ax,50
  1347.     adc    dx,0            ; round up percent
  1348.     or    bx,bx            ; empty file?
  1349.     jnz    ArcV2d
  1350.      mov    ax,100
  1351.      jmp    short ArcV2e
  1352.  
  1353. ArcV2d: div    bx
  1354. ArcV2e:
  1355.     mov    di,offset vtsf-2    ;format stowage factor        v1.3
  1356.     call    Asciify            ;AX                v1.3
  1357.  
  1358.     mov    al,sign
  1359.     mov    vtsf,al
  1360.     Print    vthdr            ; display totals
  1361.     ret
  1362.  
  1363. Format_Totals    endp
  1364.  
  1365.  
  1366. OpenArc proc    near            ; open new archive
  1367.  
  1368.     mov    dx,offset arcname
  1369.     mov    ax,3d00h        ; for input
  1370.     int    21h
  1371.     jnb    Open_GetSize        ;opened ok            v1.3a
  1372.      ret                ;return CF set, AL=error    v1.3a
  1373.  
  1374. Open_GetSize:
  1375.     mov    bx,ax            ;handle into BX            v1.3a
  1376.     mov    archdl,ax        ; save file handle
  1377.  
  1378. ;v1.3a    We get the total file size now for later EOF testing.
  1379.     xor    dx,dx            ;0 offset
  1380.     xor    cx,cx
  1381.     mov    ax,4202H        ;from file end
  1382.     int    21H
  1383.     mov    filelen,ax        ;length.low
  1384.     mov    filelen[2],dx        ;length.hi
  1385.     xor    cx,cx            ;back to start
  1386.     xor    dx,dx
  1387.     mov    ax,4200H        ;psn file pointer from start
  1388.     int    21H
  1389.     ret                ;CF should be clear
  1390.  
  1391. OpenArc endp
  1392.  
  1393.  
  1394. ClosArc proc    near
  1395.  
  1396.     mov    bx,archdl        ; previous handle
  1397.     or    bx,bx            ; already open?
  1398.     jz    Closed
  1399.      mov    ah,3eh            ; yes, so close it
  1400.      int    21H
  1401. Closed:    mov    archdl,0        ;flag as closed
  1402.     ret
  1403.  
  1404. ClosArc endp
  1405.  
  1406. ;
  1407. ;    print null-terminated (AsciiZ) string like int 21h function 9
  1408. ;    Enter with DS:DX -> AsciiZ string
  1409. ;    destroys AX
  1410. ;    On success, return:
  1411. ;     CF clear
  1412. ;     AL = 0
  1413. ;    On failure (write fail), return:
  1414. ;     CF set
  1415. ;     AL = error
  1416.  
  1417. PrintS  proc    near
  1418.  
  1419.     push    di            ;v1.3
  1420.     push    bx
  1421.     push    cx
  1422.  
  1423.     mov    cx,0FFFFH        ;max scan            v1.3
  1424.     xor    al,al            ;handy 0            v1.3
  1425.     mov    di,dx            ;string start            v1.3
  1426.     repne    scasb            ;find the terminator        v1.3
  1427.     inc    cx            ;adjust                v1.3
  1428.     not    cx            ;CX=length            v1.3
  1429.  
  1430.     mov    bx,outhdl        ; using std out or temp file
  1431.     or    bx,bx            ;never opened?            v1.3
  1432.     jnz    Print_S1        ;nope, we got a handle        v1.3
  1433.      inc    bx            ;make it StdErr            v1.3
  1434.      inc    bx
  1435. Print_S1:                ;                v1.3
  1436.     mov    ah,40h            ; write to file
  1437.     int    21h
  1438.     jnb    PrintS_Done        ;fine                v1.3
  1439.  
  1440. ;v1.3    What happens if we're trying to write to an output file
  1441. ;    and THAT fails?  Even error msgs can't get out.
  1442. ;    We switch to StdErr, that's what!
  1443.  
  1444.     mov    di,ax            ;save error level        v1.3a
  1445.     mov    bx,STDERR        ;force to STdErr        v1.3a
  1446.     mov    outhdl,bx        ;and for future output        v1.3a
  1447.     mov    ah,40H            ;write to STDOUT        v1.3a
  1448.     int    21H            ;(CX,DX unchanged)        v1.3a
  1449.     mov    ax,di            ;restore orig error        v1.3a
  1450.     stc                ;return CF set            v1.3a
  1451.  
  1452. PrintS_Done:
  1453.     pop    cx            ; recover registers
  1454.     pop    bx
  1455.     pop    di
  1456.     ret
  1457.  
  1458. PrintS  endp
  1459.  
  1460.     page
  1461. ;
  1462. ;    format the time (in AX)
  1463.  
  1464. time    record  hour:5,min:6,sec:5    ;packed time
  1465.  
  1466. GetTime proc    near            ;format the date
  1467.     mov    di,offset vtime
  1468.     or    ax,ax            ;it is zero?
  1469.     jz    GotTime
  1470.  
  1471.     push    ax            ;save date
  1472.     and    ax,mask hour        ;get hour part
  1473.     mov    cl,hour            ;bits to shift
  1474.     shr    ax,cl
  1475.     call    Cnvrt1
  1476.     stosw
  1477.     mov    al,':'
  1478.     stosb
  1479.  
  1480. GT3:    pop    ax            ;get the time back
  1481.     and    ax,mask min        ;get min part
  1482.     mov    cl,min            ;bits to shift
  1483.     call    Cnvrt
  1484.     stosw
  1485. GotTime:ret
  1486. GetTime endp
  1487.  
  1488.  
  1489. Cnvrt2  proc    near            ;convert to ascii
  1490.     call    Cnvrt
  1491.     cmp    al,'0'            ;suppress leading zero
  1492.     jne    Cnvrtd
  1493.      mov    al,' '
  1494.      ret
  1495.  
  1496. Cnvrt:  shr    ax,cl
  1497. Cnvrt1: aam                ;make al into bcd
  1498.     or    ax,'00'            ; and to ascii
  1499.     xchg    al,ah
  1500. Cnvrtd: ret
  1501. Cnvrt2  endp
  1502.  
  1503.     page
  1504. ;
  1505. ;    format the date (in AX)
  1506.  
  1507. date    record  yr:7,mo:4,dy:5        ;packed date
  1508.  
  1509. GetDate proc    near            ;format the date
  1510.     or    ax,ax            ;is it zero?
  1511.     jz    GotDate
  1512.  
  1513.     push    ax            ;save date
  1514.     and    ax,mask yr        ;get year part
  1515.     mov    cl,yr            ;bits to shift
  1516.     call    Cnvrt
  1517.     mov    di,offset vyear
  1518.     or    al,'8'            ;adjust for base year
  1519.     stosw
  1520.  
  1521.     pop    bx            ;get the date back
  1522.     push    bx            ;save it
  1523.     and    bx,mask mo        ;get month part
  1524.     mov    cl,mo            ;bits to shift
  1525.     shr    bx,cl
  1526.     add    bx,bx            ; form month table index
  1527.     add    bx,bx
  1528.     lea    si,word ptr months-4[bx]
  1529.     mov    cx,word ptr 3
  1530.     mov    di,offset vmonth
  1531.     rep    movsb
  1532.  
  1533.     pop    ax            ;get the date back
  1534.     and    ax,mask dy        ;get day part
  1535.     mov    cl,dy            ;bits to shift
  1536.     call    Cnvrt
  1537.     mov    di,offset vdate
  1538.     stosw
  1539. GotDate:ret
  1540. GetDate endp
  1541.  
  1542.     page
  1543. ;
  1544. ;v1.3    A severely hacked single/double precision number conversion function.
  1545. ;    Originally from JMODEM, but severely hacked by Toad Hall.
  1546. ;    ES:DI -> string
  1547. ;    Destroys everything almost.
  1548.  
  1549. ;Enter here if integer in AX
  1550. Asciify    proc    near
  1551.  
  1552.     xor    dx,dx            ; clear fake long.hi
  1553.     mov    si,ax            ;move integer into SI
  1554.     xor    ah,ah            ;clear msb (flag)
  1555.     jmp    short Ascii_Ax        ;jump into the code
  1556.  
  1557. ;Enter here if long integer in DX:AX.
  1558. Asciify_Long:
  1559.  
  1560.     mov    si,ax            ;move long.lo into SI
  1561.     xor    ah,ah            ;clear msb (flag)
  1562. Comment    ~
  1563.     MOV    CX,3B9AH        ; Get billions
  1564.     MOV    BX,0CA00H
  1565.     CALL    Subtr            ; Subtract them out
  1566.  
  1567.     MOV    CX,05F5H        ; Get hundred-millions
  1568.     MOV    BX,0E100H
  1569.     CALL    Subtr            ; Subtract them out
  1570. Comment    ends    ~
  1571.  
  1572.     and    dx,4FFH            ;seems likely            v1.3
  1573.     MOV    CX,word ptr 0098H    ; Get ten-millions
  1574.     MOV    BX,9680H
  1575.     CALL    Subtr            ; Subtract them out
  1576.  
  1577.     MOV    CX,word ptr 000FH    ; Get millions
  1578.     MOV    BX,4240H
  1579.     CALL    Subtr            ; Subtract them out
  1580.  
  1581.     MOV    CX,word ptr 1        ; Get hundred-thousands
  1582.     MOV    BX,86A0H
  1583.     CALL    Subtr            ; Subtract them out
  1584.  
  1585. Ascii_Ax:
  1586.     xor    cx,cx            ; Get ten-thousands
  1587.     MOV    BX,2710H
  1588.     CALL    Subtr            ; Subtract them out
  1589.     MOV    BX,03E8H
  1590.     CALL    Subtr            ; Subtract them out
  1591.  
  1592.     MOV    BX,word ptr 0064H
  1593.     CALL    Subtr            ; Subtract them out
  1594.     MOV    BX,word ptr 10
  1595.     CALL    Subtr            ; Subtract them out
  1596.     mov    ax,si            ;residual in SI
  1597.     add    AL,'0'            ; Add bias to residual
  1598.     stosb                ; Put in the string
  1599.     RET
  1600.  
  1601. ;Common subroutine for Asciify
  1602.  
  1603. Subtr:    mov    al,'0'-1
  1604.  
  1605. Subtr1:    INC    al            ; Bump the digit character
  1606.     SUB    si,BX            ; Dword subtraction
  1607.     SBB    DX,CX
  1608.     JNB    Subtr1            ; Continue until a carry
  1609.  
  1610.     ADD    si,BX            ; One too many, add back
  1611.     ADC    DX,CX            ;   and the remainder
  1612.  
  1613.     cmp    al,'0'
  1614.     jnz    Subtr2            ;nope, turn off leading flag, stuff
  1615.      or    ah,ah            ;no more leading spaces?
  1616.      jnz    Sub_Stuff        ;right, stuff the '0'
  1617.       mov    al,' '            ;make it neat with leading spaces
  1618. Sub_Stuff:
  1619.     stosb                ;stuff the char
  1620.     RET
  1621.  
  1622. Subtr2:    inc    ah            ;turn off leading space flag
  1623.     stosb
  1624.     ret
  1625. Asciify    ENDP
  1626.  
  1627.  
  1628. ;v1.3a    Convert 16-bit binary word in AX
  1629. ;    to hex ASCII string at ES:DI
  1630. ;    (No need to save any registers)
  1631.  
  1632. hexchar db    '0123456789ABCDEF'
  1633.  
  1634. Cvh    proc    near
  1635.  
  1636.     mov    si,offset hexchar    ;for faster access        v1.3a
  1637.     mov    dx,ax            ; save 16-bits
  1638.  
  1639.     mov    bl,dh            ; third nibble
  1640.     mov    cx,0F04H        ;CL=4 for shifting,        v1.3a
  1641.                     ;CH=0FH for masking        v1.3a
  1642.     shr    bl,cl
  1643.     mov    al,[si][bx]        ;snarf hex char            v1.3a
  1644.     stosb
  1645.  
  1646.     mov    bl,dh            ; last nibble
  1647.     and    bl,ch    ;0fh        ;                v1.3a
  1648.     mov    al,[si][bx]        ;snarf hex char            v1.3a
  1649.     stosb
  1650.  
  1651.     mov    bl,dl            ; first nibble
  1652.     sub    bh,bh
  1653.     shr    bl,cl            ; isolate (CL still 4)        v1.3a
  1654.     mov    al,[si][bx]        ;snarf hex char            v1.3a
  1655.     stosb
  1656.  
  1657.     mov    bl,dl            ; second nibble
  1658.     and    bl,ch    ;0fh        ; isolate            v1.3a
  1659.     mov    al,[si][bx]        ;snarf hex char            v1.3a
  1660.     stosb
  1661.     ret
  1662.  
  1663. Cvh    endp
  1664.  
  1665.     subttl    '--- i/o data areas'
  1666.  
  1667. ArcV    endp
  1668.  
  1669. archdr  db    30 dup (0)        ; i/o area for a header        v1.3a
  1670.  
  1671. inbuf    db    INBUFSZ dup (0)        ;just big enough for ZIP
  1672.                     ;directories and filenames    v1.3a
  1673.  
  1674. CSEG    ENDS
  1675.     END
  1676.